/**
 * edurender
 * Quake3Model.h
 * (c) 2009 J. Brad Byrd
 */

#ifndef ER_QUAKE3MODEL_H
#define ER_QUAKE3MODEL_H

#include "DXUT.h"

#include <cstdio>
#include <vector>

namespace er
{
	class Quake3ModelReader
	{
	public:
		class Frame;
		class Tag;
		class Surface;

	public:
		enum { MAX_QPATH = 64 };
		static const float MD3_XYZ_SCALE;

	public:
		static Quake3ModelReader *Create(const char *fileName);
		static void Destroy(Quake3ModelReader *model);
		
	public:
		unsigned __int32 GetSurfaceCount() { return m_surfaces.size(); }
		const Surface *GetSurface(unsigned __int32 index) { return &m_surfaces[index]; }
	
	private:
		std::vector<Frame> m_frames;
		std::vector<Tag> m_tags;
		std::vector<Surface> m_surfaces;
	
	private:
		Quake3ModelReader();
		bool Read(const char *fileName);

	private:
		Quake3ModelReader(const Quake3ModelReader &);
		Quake3ModelReader &operator=(const Quake3ModelReader &);

	public:
		class Frame
		{
		public:
			const D3DXVECTOR3 &GetMinBounds() const { return m_minBounds; }
			const D3DXVECTOR3 &GetMaxBounds() const { return m_maxBounds; }
			const D3DXVECTOR3 &GetLocalOrigin() const { return m_localOrigin; }
			float GetRadius() const { return m_radius; }
			const char *GetName() const { return m_name; }
			
		private:
			friend bool Quake3ModelReader::Read(const char *);
			void Read(FILE *fp);
			
		private:
			enum { MAX_NAME = 16 };
		
		private:
			D3DXVECTOR3 m_minBounds;
			D3DXVECTOR3 m_maxBounds;
			D3DXVECTOR3 m_localOrigin;
			float m_radius;
			char m_name[MAX_NAME];
		};

		class Tag
		{
		public:
			enum Axis
			{
				X_AXIS,
				Y_AXIS,
				Z_AXIS,
			};
		
		public:
			const char *GetName() const { return m_name; }
			const D3DXVECTOR3 &GetOrigin() const { return m_origin; }
			const D3DXVECTOR3 &GetAxis(Axis axis) const { return m_axis[axis]; }
			
		private:
			friend bool Quake3ModelReader::Read(const char *);
			void Read(FILE *fp);
			
		private:
			char m_name[MAX_QPATH];
			D3DXVECTOR3 m_origin;
			D3DXVECTOR3 m_axis[3];
		};

		struct XyzNormal
		{
			__int16 x, y, z;
			__int16 normal;
		};

		class Surface
		{
		public:
			const char *GetName() const { return m_name; }
			unsigned __int32 GetIndexCount() const { return m_indices.size(); }
			const unsigned __int32 *GetIndices() const { return &m_indices[0]; }
			unsigned __int32 GetTexCoordCount() const { return m_texCoords.size(); }
			const D3DXVECTOR2 *GetTexCoords() const { return &m_texCoords[0]; }
			unsigned __int32 GetFrameCount() const { return m_frameCount; }
			unsigned __int32 GetXyzNormalsCount() const { return m_vertCount; }
			const XyzNormal *GetXyzNormals(unsigned __int32 frame) const
			{
				return (frame < m_frameCount) ? &m_xyzNormals[frame * m_vertCount] : 0;
			}
			
		private:
			friend bool Quake3ModelReader::Read(const char *);
			void Read(FILE *fp);

		private:
			unsigned __int32 m_frameCount;
			unsigned __int32 m_vertCount;
			char m_name[MAX_QPATH];
			std::vector<unsigned __int32> m_indices;
			std::vector<D3DXVECTOR2> m_texCoords;
			std::vector<XyzNormal> m_xyzNormals;
		};
		
	};
}

#endif // ER_QUAKE3MODEL_H
